// ---------------------------------------------------------------------------
var Component = Class.create();
Component.prototype = {
    initialize: function(identity) {
        this._identity = identity;
    },
    getIdentity: function() {
        return this._identity;
    }
};

// ---------------------------------------------------------------------------
var Entity = Class.create();
Entity.prototype = Object.extend(new Component(), {
    initialize: function(identity, title) {
        this._identity = identity;
        this._title = title;
        this._visible = false;
        this._templates = $H({
           'input'      : new Template("<input type='#{type}' name='#{component}' id='#{identity}' value='#{identity}' />&nbsp;#{title}"),
           'listItem'   : new Template("<li>#{content}</li>")
        });
    },
    getTitle: function() {
        return this._title;
    },
    isVisible: function() {
        return this._visible;
    },
    show: function() {
        this._visible = true;
    },
    hide: function() {
        this._visible = false;
    },
    toggle: function() {
        this._visible = !this.visible;
    },
    toString: function() {
        return this.getTitle() + ' (' + this.getIdentity() + ')';
    },
    toInput: function(type, component) {
        return this._templates['input'].evaluate({
            'type'      : type,
            'component' : component.getIdentity(),
            'title'     : this.getTitle(),
            'identity'  : this.getIdentity()
        });
    },
    toListItem: function(type, component) {
        return this._templates['listItem'].evaluate({ 'content' : this.toInput(type, component) });
    }
});

// ---------------------------------------------------------------------------
var EntityChooser = Class.create();
EntityChooser.prototype = Object.extend(new Component(), {
    initialize: function(identity, base) {
        this._identity = identity;
        this._base = base;
        this._URLs = $H({ search : 'ajax_performSearch' });
        
        this._searchSet = $A();
        this._selectedSet = $A();
    },
    // -----------------------------------------------------------------------
    getSearchSet: function() {
        return this._searchSet;
    },
    setSearchSet: function(enumerable) {
        this._searchSet = enumerable;
    },
    setSearchSetFromJSON: function(json) {
        this.setSearchSet( json.map( function(x) { return new Entity(x['identity'], x['title']) } ) );
    },
    // -----------------------------------------------------------------------
    getSelectedSet: function() {
        return this._selectedSet;
    },
    setSelectedSet: function(enumerable) {
        this._selectedSet = enumerable;
    },
    // -----------------------------------------------------------------------
    getUnselectedSet: function() {
        var selectedSetIds = this.getSelectedSet().invoke('getIdentity');
        return this.getSearchSet().select(
            function(entity) {
                return !selectedSetIds.include(entity.getIdentity());
            }
        );
    },
    // -----------------------------------------------------------------------
    markSelected: function(entityIdentities) {
        var entities = this.getUnselectedSet().findAll(
            function(entity) {
                return entityIdentities.member( entity.getIdentity() );
            }
        )
        
        this.setSelectedSet(this.getSelectedSet().concat(entities).uniq());
        
        return this.getSelectedSet();
    },
    markUnselected: function(entityIdentities) {
        // Remove the selected entities
        this.setSelectedSet(
            this.getSelectedSet().select(
                function(entity) {
                    return !entityIdentities.include( entity.getIdentity() );
                }
            )
        );

        return this.getUnselectedSet();
    },
    // -----------------------------------------------------------------------
    search: function(queryString, handler) {
        var here = this;

        new Ajax.Request(
            this._base + '/' + this._URLs['search'],
            {
                method: 'get',
                parameters: {
                    componentIdentity: this.getIdentity(),
                    queryString: queryString
                },
                onSuccess: function(transport, json) {
                    here.setSearchSetFromJSON(json);

                    if (handler !== undefined) {
                        handler();
                    }
                },
                onFailure: function() {
                    alert('An AJAX request error occured.');
                }
            }
        );
    }
});

// new Template("<li><input type='#{type}' name='#{component}' id='#{identity}' value='#{identity}' />&nbsp;#{title}</li>")